#!/usr/bin/env python
# -*- encoding: utf-8 -*-
import time, sys, datetime

import ibm_db

from app.AbstractStateJob import AbstractStateJob
from app.utils.XDB2Utils import XDB2Utils
from app.models.Q602_L2_SUBPC2002 import Q602_L2_SUBPC2002
from app.models.TimeWindow import TimeWindow


class FDCLStateJob(AbstractStateJob):
    """
    以BPC的周期5s收集数据表1（DTG_C15S）为基准，当中央段速度=0时，判定为停机。开停机无需延时判定。

    停机开始时间：当速度为0则为停机开始。例：12:00:00收到一条速度=0的数据，则判定有停机事件，开始时间为12:00:00。
    停机结束时间：当速度>0则为停机结束。例：12:00:00收到最后一条速度=0的数据，则判定有停机结束，结束时间为12:00:00。

    涉及数据表与字段：
    BGROQ512.Q512_L2_DTG_C15S.UP_DATE			记录时间
    BGROQ512.Q512_L2_DTG_C15S.CNT_LINE_SPEED	中央线速度

    SQL中314，412，502对应的是文档中FCL DCL 和RCM







    程序开始执行
    选择需要判断的机组（例如DCL4  Q412）
    读取停机表（0002），查找Q412的最后一次停机数据
    此时有两种情况
    无记录（首次）, 有记录

    无记录，执行
    判断期间是否发生过停机
    【期间的起止定义，无记录时从最早一条数据开始，到当前最后一条数据】
    走停机判读逻辑

    BGROQ512.Q512_L2_DTG_C15S表中
    CNT_LINE_SPEED 中央线速度
    Speed为0开始停机speed>0结束停机
    得到期间发生过的每次  停机ed  的情况

    判断是否有停机ing，最后一条记录是否是speed为0
    如果为0则判断成停机ing  写入停机表 只有开始时间  无结束时间  或二者相同  具体要看需求的记录逻辑
    最后
    将期间发生过的每次记录按照时间顺序最后一起写入到停机表中

    有记录时，判断最后一次停机数据的状态，停机ing  或者   停机ed
    【最后一次用日期加开始停机时间排序】
    【停机数据的写表记录逻辑，需要确认一下】
    如果是停机ing  判断是否是特殊情况，不是特殊情况后，
    特殊情况零星出现一个0  or  出现一个>0

    将期间范围  定义成  停机ing的开始时间~ now
    如果是停机ed
    期间定义成  （上次判定时间 or 上次停机结束时间）~now
    """

    #
    UNIT_CODES_DCL = ['Q112', 'Q212', 'Q312', 'Q412']
    UNIT_CODES_FCL = ['Q114', 'Q214', 'Q314', 'Q414']

    #
    TYPE_DCL = 'DCL'
    TYPE_FCL = 'FCL'
    type = None

    def __init__(self, p_config=None, p_unit_code: str = None):
        """

        :param p_config:
        :param p_type: should be one of DCLStateJob.TYPE_DCL and DCLStateJob.TYPE_FCL
        """
        super(FDCLStateJob, self).__init__(p_config=p_config, p_unit_code=p_unit_code)
        #self.type = FDCLStateJob.TYPE_DCL if p_type is None else p_type
        pass

    def execute(self):
        print('DCLStateJob.execute')

        self.__do_execute()

        # close db
        super(FDCLStateJob, self).execute()
        pass

    def __do_execute(self):
        """
        读取停机表（BGTARAS1.T_DWD_WH_ZZSC_JZ_SU_QALL_0002），查找Q412的最后一次停机数据
        select MAX(SD_END) from BGTARAS1.T_DWD_WH_ZZSC_JZ_SU_QALL_0002 where UNIT_CODE='Q412'
        判断是否有数据
        此时会有两种情况
        无记录（首次）, 有记录

        无记录，
        执行
        判断期间发生过几次停机（开始时间，结束时间）
        """
        # NOTE 机组代码。 DCL里面就有几个机器 Q112，Q212,Q312,Q412， 先写死Q412机组
        # 判断就是QX12,QX14走DCL；
        # NOTE QX14 是FCL的。 sql逻辑也一样的  只需要换schema
        # 第一步就去查了这个机器最后一次停机时间
        # 如果没查到。就全查，或者把开始时间设为当前时间的钱几天
        start_time = (datetime.datetime.now() + datetime.timedelta(days=-40)).strftime('%Y%m%d%H%M%S')
        end_time = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
        sql = "select MAX(SHUTDOWN_END) as TMP_MAX from BGTARAS1.T_DWD_WH_SBOPSI_JZ_SU_QALL_0002_test where UNIT_CODE='%s'" % (self.unit_code)
        success, results = XDB2Utils.fetchall_sql(p_sql=sql, p_conn=self.conn)
        print('\n第一步就去查了这个机器最后一次停机时间:')
        print(results)
        if success and len(results) > 0 and results[0]['TMP_MAX'] is not None:
            start_time = results[0]['TMP_MAX']

        print('go to __fetch_all_shutdown_time_windows_in')
        time_window_list = self.__fetch_all_shutdown_time_windows_in(p_unit_code=self.unit_code, p_start_date=start_time, p_end_date=end_time)
        self.__save_all_shutdown_time_windows_2_db(p_unit_code=self.unit_code, p_time_window_list=time_window_list)

    def __fetch_all_shutdown_time_windows_in(self, p_unit_code: str = None, p_start_date=None, p_end_date=None) -> (list):
        """
        期间发生过几次停机（开始时间，结束时间）

        从C15s表读取数据了

        然后数据是按照时间排序的  ，如果第一个数据是大于0，就看下一条，直到数据是0，数据是0就是一个停机开始时间

        然后看下一条  如果还是0就在看下一条  直到遇到下一个非0，下一个非0的上一条对应的时间就是结束时间

        这就是第一段停机的开始时间与结束时间
        然后再继续找第二段停机的开始时间

        就两种情况要么大于0  要么等于0
        然后相当于把一串数字中一段一段的0给挑出来
        :return:
        """
        time_window_list = list()
        # 读停机表
        # 就是DCL  里面就有几个机器 Q112，Q212,Q312,Q412
        # 每一个机器都有一个库
        # 然后相同结尾的  逻辑完全一样
        # 所以就先随便选一个
        # Select UP_DATE,CNT_LINE_SPEED from BGTAROQ412.DTG_C15S where cast(COALESCE(UP_DATE, '0') as bigint)>=20201023114003 and cast(COALESCE(UP_DATE, '0') as bigint)<=20201030164416 order by UP_DATE
        sql = "Select UP_DATE, CNT_LINE_SPEED from BGTARO%s.DTG_C15S where UP_DATE>%s and UP_DATE<%s order by UP_DATE" % (p_unit_code, p_start_date, p_end_date)
        success, results = XDB2Utils.fetchall_sql(p_sql=sql, p_conn=self.conn)
        print('\n__fetch_all_shutdown_time_windows_in  读停机表:')
        print('一共有 %d 条停机数据' % (len(results)))
        if success:
            prev_entry = None
            curr_entry = None
            # init an invalid time window
            time_window = TimeWindow(p_start_time=None, p_end_time=None)

            # 30号  27号 都有一次
            for index, r in enumerate(results):
                if index > 0:
                    t = results[index - 1]
                    prev_entry = Q602_L2_SUBPC2002(p_speed=t['CNT_LINE_SPEED'], p_date_time=t['UP_DATE'])
                curr_entry = Q602_L2_SUBPC2002(p_speed=r['CNT_LINE_SPEED'], p_date_time=r['UP_DATE'])

                if time_window.start_time is None and curr_entry.SPEED == 0:
                    time_window.start_time = curr_entry.DATE_TIME
                    # print('start_time------->>>'.format(time_window.start_time))
                    continue

                if prev_entry is not None and time_window.start_time is not None and curr_entry.SPEED > 0:
                    time_window.end_time = prev_entry.DATE_TIME
                    # print('end_time------->>>'.format(time_window.end_time))
                    if time_window.is_valid():
                        time_window_list.append(time_window)
                    # NOTE reset
                    time_window = TimeWindow(p_start_time=None, p_end_time=None)
        print('\ntime_window_list  所有停机时间:')
        for element in time_window_list:
            print('%s %s' % (str(element.start_time), str(element.end_time)))
        return time_window_list

    def __save_all_shutdown_time_windows_2_db(self, p_unit_code: str = None, p_time_window_list: list = None) -> (bool):
        """
        # 将其他的信息写入到数据库
        #
        """
        # 分别就是一开始查询的那QXXX，停机开始的日期，小时单位的停机时间差，开始时间，结束时间，分钟单位的停机时间差
        # UNIT_CODE, SHUTDOWN_DATE, SHUTDOWN_TIME, SHUTDOWN_START, SHUTDOWN_END, SHUTDOWN_MINUTE
        p_sql = "INSERT INTO BGTARAS1.T_DWD_WH_SBOPSI_JZ_SU_QALL_0002_test(UNIT_CODE, SHUTDOWN_DATE, SHUTDOWN_TIME, SHUTDOWN_START, SHUTDOWN_END, SHUTDOWN_MINUTE) values('%s','%s','%s','%s','%s','%s')"
        for o in p_time_window_list:
            sql = "select * from BGTARAS1.T_DWD_WH_SBOPSI_JZ_SU_QALL_0002_test where UNIT_CODE='%s' AND SHUTDOWN_START='%s' AND SHUTDOWN_END='%s'" % (
                self.unit_code, str(o.start_time), str(o.end_time))
            success, results = XDB2Utils.fetchall_sql(p_sql=sql, p_conn=self.conn)
            if len(results) == 0:
                param = list()
                SHUTDOWN_DATE = datetime.datetime.strptime(str(o.start_time), '%Y%m%d%H%M%S').strftime('%Y%m%d')  # 停机开始的日期
                # NOTE 用时间减法, 不能用数字减法
                # SHUTDOWN_MINUTE = (o.end_time - o.start_time) / 60  # 分钟单位的停机时间差
                time_2_struct = datetime.datetime.strptime(str(o.end_time), '%Y%m%d%H%M%S')
                time_1_struct = datetime.datetime.strptime(str(o.start_time), '%Y%m%d%H%M%S')
                SHUTDOWN_MINUTE = (time_2_struct - time_1_struct).seconds / 60
                SHUTDOWN_TIME = SHUTDOWN_MINUTE / 60  # 小时单位的停机时间差
                t = (str(p_unit_code),
                     str(SHUTDOWN_DATE),
                     str(SHUTDOWN_TIME),
                     str(o.start_time),
                     str(o.end_time),
                     str(SHUTDOWN_MINUTE))
                param.append(t)
            success = XDB2Utils.executemany_sql(p_sql=p_sql, p_conn=self.conn, p_param=param)
        return True

